package com.mas.framework.security.core.filter;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.mas.admin.api.oauth2.OAuth2TokenApi;
import com.mas.admin.api.oauth2.dto.OAuth2AccessTokenCheckRespDTO;
import com.mas.framework.common.pojo.CommonResult;
import com.mas.framework.common.util.servlet.ServletUtils;
import com.mas.framework.security.config.SecurityProperties;
import com.mas.framework.security.core.pojo.LoginUser;
import com.mas.framework.security.core.util.SecurityFrameworkUtils;
import com.mas.framework.web.core.handler.GlobalExceptionHandler;
import com.mas.framework.web.core.util.WebFrameworkUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;


/**
 * Token 过滤器，验证 token 的有效性
 * @author godyao
 * @description 验证通过后，获得 {@link LoginUser} 信息，并加入到 Spring Security 上下文
 * @date 2023年01月29日20:44
 */
@Slf4j
@RequiredArgsConstructor
public class TokenAuthenticationFilter extends OncePerRequestFilter {

    private final SecurityProperties securityProperties;
    private final GlobalExceptionHandler globalExceptionHandler;
    private final OAuth2TokenApi oauth2TokenApi;


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        final String authorization = SecurityFrameworkUtils.obtainAuthorization(request, securityProperties.getTokenHeader());
        if (StrUtil.isNotBlank(authorization)) {
            try {
                // 获取登陆用户类型
                Integer userType = WebFrameworkUtils.getLoginUserType(request);
                // 1.1 基于 token 构建登录用户
                LoginUser loginUser = buildLoginUserByToken(authorization, userType);
                if (loginUser != null) {
                    SecurityFrameworkUtils.setLoginUser(loginUser, request);
                }
            } catch (Exception e) {
                CommonResult<?> result = globalExceptionHandler.allExceptionHandler(request, e);
                ServletUtils.writeJSON(response, result);
                return;
            }
        }
        filterChain.doFilter(request, response);
    }

    private LoginUser buildLoginUserByToken(String token, Integer userType) {
        try {
            // 校验令牌有效性
            final OAuth2AccessTokenCheckRespDTO accessToken = oauth2TokenApi.checkAccessToken(token);
            if (Objects.isNull(accessToken)) {
                return null;
            }
            if (ObjectUtil.notEqual(accessToken.getUserType(), userType)) {
                throw new AccessDeniedException("错误的用户类型");
            }
            // 构建登录用户
            return new LoginUser()
                    .setUserType(userType)
                    .setId(accessToken.getUserId())
                    .setScopes(accessToken.getScopes())
                    .setTenantId(accessToken.getTenantId());
        } catch (AccessDeniedException e) {
            return null;
        }

    }

}
